<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>Keyboard Lock</title>
  <link href="https://www.w3.org/StyleSheets/TR/2016/cg-draft" rel="stylesheet" type="text/css">
  <link href="https://wicg.github.io/keyboard-lock/" rel="canonical">
<style>/* style-md-lists */

/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}</style>
<style>/* style-selflinks */

.heading, .issue, .note, .example, li, dt {
    position: relative;
}
a.self-link {
    position: absolute;
    top: 0;
    left: calc(-1 * (3.5rem - 26px));
    width: calc(3.5rem - 26px);
    height: 2em;
    text-align: center;
    border: none;
    transition: opacity .2s;
    opacity: .5;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* style-counters */

body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}</style>
<style>/* style-var-click-highlighting */

    var { cursor: pointer; }
    var.selected0 { background-color: #F4D200; box-shadow: 0 0 0 2px #F4D200; }
    var.selected1 { background-color: #FF87A2; box-shadow: 0 0 0 2px #FF87A2; }
    var.selected2 { background-color: #96E885; box-shadow: 0 0 0 2px #96E885; }
    var.selected3 { background-color: #3EEED2; box-shadow: 0 0 0 2px #3EEED2; }
    var.selected4 { background-color: #EACFB6; box-shadow: 0 0 0 2px #EACFB6; }
    var.selected5 { background-color: #82DDFF; box-shadow: 0 0 0 2px #82DDFF; }
    var.selected6 { background-color: #FFBCF2; box-shadow: 0 0 0 2px #FFBCF2; }
    </style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}</style>
<style>/* style-dfn-panel */

.dfn-panel {
    position: absolute;
    z-index: 35;
    height: auto;
    width: -webkit-fit-content;
    width: fit-content;
    max-width: 300px;
    max-height: 500px;
    overflow: auto;
    padding: 0.5em 0.75em;
    font: small Helvetica Neue, sans-serif, Droid Sans Fallback;
    background: #DDDDDD;
    color: black;
    border: outset 0.2em;
}
.dfn-panel:not(.on) { display: none; }
.dfn-panel * { margin: 0; padding: 0; text-indent: 0; }
.dfn-panel > b { display: block; }
.dfn-panel a { color: black; }
.dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; }
.dfn-panel > b + b { margin-top: 0.25em; }
.dfn-panel ul { padding: 0; }
.dfn-panel li { list-style: inside; }
.dfn-panel.activated {
    display: inline-block;
    position: fixed;
    left: .5em;
    bottom: 2em;
    margin: 0 auto;
    max-width: calc(100vw - 1.5em - .4em - .5em);
    max-height: 30vh;
}

.dfn-paneled { cursor: pointer; }
</style>
<style>/* style-syntax-highlighting */
pre.idl.highlight { color: #708090; }
.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
c-[a] { color: #990055 } /* Keyword.Declaration */
c-[b] { color: #990055 } /* Keyword.Type */
c-[c] { color: #708090 } /* Comment */
c-[d] { color: #708090 } /* Comment.Multiline */
c-[e] { color: #0077aa } /* Name.Attribute */
c-[f] { color: #669900 } /* Name.Tag */
c-[g] { color: #222222 } /* Name.Variable */
c-[k] { color: #990055 } /* Keyword */
c-[l] { color: #000000 } /* Literal */
c-[m] { color: #000000 } /* Literal.Number */
c-[n] { color: #0077aa } /* Name */
c-[o] { color: #999999 } /* Operator */
c-[p] { color: #999999 } /* Punctuation */
c-[s] { color: #a67f59 } /* Literal.String */
c-[t] { color: #a67f59 } /* Literal.String.Single */
c-[u] { color: #a67f59 } /* Literal.String.Double */
c-[cp] { color: #708090 } /* Comment.Preproc */
c-[c1] { color: #708090 } /* Comment.Single */
c-[cs] { color: #708090 } /* Comment.Special */
c-[kc] { color: #990055 } /* Keyword.Constant */
c-[kn] { color: #990055 } /* Keyword.Namespace */
c-[kp] { color: #990055 } /* Keyword.Pseudo */
c-[kr] { color: #990055 } /* Keyword.Reserved */
c-[ld] { color: #000000 } /* Literal.Date */
c-[nc] { color: #0077aa } /* Name.Class */
c-[no] { color: #0077aa } /* Name.Constant */
c-[nd] { color: #0077aa } /* Name.Decorator */
c-[ni] { color: #0077aa } /* Name.Entity */
c-[ne] { color: #0077aa } /* Name.Exception */
c-[nf] { color: #0077aa } /* Name.Function */
c-[nl] { color: #0077aa } /* Name.Label */
c-[nn] { color: #0077aa } /* Name.Namespace */
c-[py] { color: #0077aa } /* Name.Property */
c-[ow] { color: #999999 } /* Operator.Word */
c-[mb] { color: #000000 } /* Literal.Number.Bin */
c-[mf] { color: #000000 } /* Literal.Number.Float */
c-[mh] { color: #000000 } /* Literal.Number.Hex */
c-[mi] { color: #000000 } /* Literal.Number.Integer */
c-[mo] { color: #000000 } /* Literal.Number.Oct */
c-[sb] { color: #a67f59 } /* Literal.String.Backtick */
c-[sc] { color: #a67f59 } /* Literal.String.Char */
c-[sd] { color: #a67f59 } /* Literal.String.Doc */
c-[se] { color: #a67f59 } /* Literal.String.Escape */
c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */
c-[si] { color: #a67f59 } /* Literal.String.Interpol */
c-[sx] { color: #a67f59 } /* Literal.String.Other */
c-[sr] { color: #a67f59 } /* Literal.String.Regex */
c-[ss] { color: #a67f59 } /* Literal.String.Symbol */
c-[vc] { color: #0077aa } /* Name.Variable.Class */
c-[vg] { color: #0077aa } /* Name.Variable.Global */
c-[vi] { color: #0077aa } /* Name.Variable.Instance */
c-[il] { color: #000000 } /* Literal.Number.Integer.Long */
</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"><a class="logo" href="https://www.w3.org/"> <img alt="W3C" height="48" src="https://www.w3.org/StyleSheets/TR/2016/logos/W3C" width="72"> </a> </p>
   <h1>Keyboard Lock</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Draft Community Group Report, <time class="dt-updated" datetime="1970-01-01">1 January 1970</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="https://wicg.github.io/keyboard-lock/">https://wicg.github.io/keyboard-lock/</a>
     <dt>Previous Versions:
     <dd><a href rel="prev"></a>
     <dd><a href="<none>" rel="prev">&lt;none></a>
     <dt class="editor">Editors:
     <dd class="editor p-author h-card vcard"><span class="p-name fn"></span>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:garykac@google.com">Gary Kacmarcik</a> (<span class="p-org org">Google</span>)
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:jamiewalch@google.com">Jamie Walch</a> (<span class="p-org org">Google</span>)
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <p class="copyright" data-fill-with="copyright"><a href="https://www.w3.org/Consortium/Legal/ipr-notice#Copyright">Copyright</a> © 1970 <a href="https://www.w3.org/"><abbr title="World Wide Web Consortium">W3C</abbr></a><sup>®</sup> (<a href="https://www.csail.mit.edu/"><abbr title="Massachusetts Institute of Technology">MIT</abbr></a>, <a href="https://www.ercim.eu/"><abbr title="European Research Consortium for Informatics and Mathematics">ERCIM</abbr></a>, <a href="httsp://www.keio.ac.jp/">Keio</a>, <a href="https://ev.buaa.edu.cn/">Beihang</a>). W3C <a href="https://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer">liability</a>, <a href="https://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks">trademark</a> and <a href="https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document" rel="license">permissive document license</a> rules apply. </p>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>This specification defines an API that allows websites to

	capture keys that are normally reserved by the underlying host
	operating system. It is intended to be used by web
	applications that provide a fullscreen immersive experience
	(like games or remote access apps).</p>
  </div>
  <h2 class="no-num no-toc no-ref heading settled" id="status"><span class="content">Status of this document</span></h2>
  <div data-fill-with="status">
   <p></p>
   <p>This document is an editor’s draft proposed as a First Public Working Draft.</p>
  </div>
  <div data-fill-with="at-risk"></div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li><a href="#introduction"><span class="secno">1</span> <span class="content">Introduction</span></a>
    <li>
     <a href="#API"><span class="secno">2</span> <span class="content">Keyboard Lock API</span></a>
     <ol class="toc">
      <li>
       <a href="#navigator-interface"><span class="secno">2.1</span> <span class="content">Navigator Interface</span></a>
       <ol class="toc">
        <li><a href="#h-navigator-keyboard"><span class="secno">2.1.1</span> <span class="content"><span>keyboard</span></span></a>
       </ol>
      <li>
       <a href="#keyboard-interface"><span class="secno">2.2</span> <span class="content">Keyboard Interface</span></a>
       <ol class="toc">
        <li><a href="#h-keyboard-lock"><span class="secno">2.2.1</span> <span class="content"><span>lock()</span></span></a>
        <li><a href="#h-keyboard-unlock"><span class="secno">2.2.2</span> <span class="content"><span>unlock()</span></span></a>
       </ol>
     </ol>
    <li>
     <a href="#handling-events"><span class="secno">3</span> <span class="content">Handling Keyboard Key Presses</span></a>
     <ol class="toc">
      <li>
       <a href="#key-press-handler"><span class="secno">3.1</span> <span class="content">System Key Press Handler</span></a>
       <ol class="toc">
        <li><a href="#registering"><span class="secno">3.1.1</span> <span class="content">Registering</span></a>
        <li><a href="#unregistering"><span class="secno">3.1.2</span> <span class="content">Unregistering</span></a>
       </ol>
      <li><a href="#handling-keyboard-events"><span class="secno">3.2</span> <span class="content">Handling Keyboard Events</span></a>
     </ol>
    <li>
     <a href="#interactions"><span class="secno">4</span> <span class="content">Intergration With Other Web Platform APIs</span></a>
     <ol class="toc">
      <li><a href="#escape-key"><span class="secno">4.1</span> <span class="content">Special Considerations with the Escape Key</span></a>
      <li><a href="#fullscreen-considerations"><span class="secno">4.2</span> <span class="content">Fullscreen Considerations</span></a>
     </ol>
    <li><a href="#pointerlock-considerations"><span class="secno">5</span> <span class="content">Pointer Lock Considerations</span></a>
    <li><a href="#mobile"><span class="secno">6</span> <span class="content">Mobile Device Considerations</span></a>
    <li><a href="#security"><span class="secno">7</span> <span class="content">Security Considerations</span></a>
    <li><a href="#privacy"><span class="secno">8</span> <span class="content">Privacy Considerations</span></a>
    <li><a href="#acknowledgements-contributors"><span class="secno">9</span> <span class="content">Acknowledgements</span></a>
    <li>
     <a href="#conformance"><span class="secno"></span> <span class="content">Conformance</span></a>
     <ol class="toc">
      <li><a href="#conventions"><span class="secno"></span> <span class="content">Document conventions</span></a>
      <li><a href="#conformant-algorithms"><span class="secno"></span> <span class="content">Conformant Algorithms</span></a>
     </ol>
    <li>
     <a href="#index"><span class="secno"></span> <span class="content">Index</span></a>
     <ol class="toc">
      <li><a href="#index-defined-here"><span class="secno"></span> <span class="content">Terms defined by this specification</span></a>
      <li><a href="#index-defined-elsewhere"><span class="secno"></span> <span class="content">Terms defined by reference</span></a>
     </ol>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#normative"><span class="secno"></span> <span class="content">Normative References</span></a>
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
    <li><a href="#idl-index"><span class="secno"></span> <span class="content">IDL Index</span></a>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="introduction"><span class="secno">1. </span><span class="content">Introduction</span><a class="self-link" href="#introduction"></a></h2>
   <p>Richly interactive web sites, games and remote
	desktop/application streaming experiences want to provide an
	immersive, full screen experience. To accomplish this, sites
	need access to special keys and keyboard shortcuts while they
	are in full screen mode so that they can be used for
	navigation, menus or gaming functionality. Some examples of
	the keys that may be required are Escape, Alt+Tab, Cmd+`, and
	Ctrl+N.</p>
   <p>By default, these keys are not available to the web application because
	they are captured by the browser or the underlying operating
	system. The Keyboard Lock API enables websites to capture and use
	all available keys allowed by the OS.</p>
   <h2 class="heading settled" data-level="2" id="API"><span class="secno">2. </span><span class="content">Keyboard Lock API</span><a class="self-link" href="#API"></a></h2>
   <h3 class="heading settled" data-level="2.1" id="navigator-interface"><span class="secno">2.1. </span><span class="content">Navigator Interface</span><a class="self-link" href="#navigator-interface"></a></h3>
<pre class="idl highlight def" data-highlight="webidl"><c- b>partial</c-> <c- b>interface</c-> <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/system-state.html#navigator" id="ref-for-navigator"><c- g>Navigator</c-></a> {
  [<a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#SecureContext" id="ref-for-SecureContext"><c- g>SecureContext</c-></a>, <a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#SameObject" id="ref-for-SameObject"><c- g>SameObject</c-></a>] <c- b>readonly</c-> <c- b>attribute</c-> <a class="n" data-link-type="idl-name" href="#keyboard" id="ref-for-keyboard"><c- n>Keyboard</c-></a> <dfn class="idl-code" data-dfn-for="Navigator" data-dfn-type="attribute" data-export data-readonly data-type="Keyboard" id="dom-navigator-keyboard"><code><c- g>keyboard</c-></code><a class="self-link" href="#dom-navigator-keyboard"></a></dfn>;
};
</pre>
   <div id="navigator-idl">
    <div class="algorithm" data-algorithm="navigator-keyboard">
     <h4 class="heading settled" data-level="2.1.1" id="h-navigator-keyboard"><span class="secno">2.1.1. </span><span class="content"><dfn class="dfn-paneled" data-dfn-for="Navigator" data-dfn-type="dfn" data-noexport id="navigator-keyboard">keyboard</dfn></span><a class="self-link" href="#h-navigator-keyboard"></a></h4>
      The <a data-link-type="dfn" href="#navigator-keyboard" id="ref-for-navigator-keyboard">keyboard</a> attribute must return the <code class="idl"><a data-link-type="idl" href="https://html.spec.whatwg.org/multipage/system-state.html#navigator" id="ref-for-navigator①">Navigator</a></code>'s <code class="idl"><a data-link-type="idl" href="#keyboard" id="ref-for-keyboard①">Keyboard</a></code> object. 
    </div>
   </div>
   <p class="note" role="note"><span>Note:</span> The <a data-link-type="dfn" href="#navigator-keyboard" id="ref-for-navigator-keyboard①">keyboard</a> object is also defined in the <a href="https://wicg.github.io/keyboard-map/#navigator-interface">Keyboard Map</a> specification. These two definitions will be reconciled once we decide on a final
		home for these specifications.</p>
   <h3 class="heading settled" data-level="2.2" id="keyboard-interface"><span class="secno">2.2. </span><span class="content">Keyboard Interface</span><a class="self-link" href="#keyboard-interface"></a></h3>
<pre class="idl highlight def" data-highlight="webidl">[<a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#SecureContext" id="ref-for-SecureContext①"><c- g>SecureContext</c-></a>, <a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#Exposed" id="ref-for-Exposed"><c- g>Exposed</c-></a>=<c- n>Window</c->] <c- b>interface</c-> <dfn class="dfn-paneled idl-code" data-dfn-type="interface" data-export id="keyboard"><code><c- g>Keyboard</c-></code></dfn> {
  <c- b>Promise</c->&lt;<c- b>void</c->> <dfn class="dfn-paneled idl-code" data-dfn-for="Keyboard" data-dfn-type="method" data-export data-lt="lock(keyCodes)|lock()" id="dom-keyboard-lock"><code><c- g>lock</c-></code></dfn>(<c- b>optional</c-> <c- b>sequence</c->&lt;<a class="idl-code" data-link-type="interface" href="https://heycam.github.io/webidl/#idl-DOMString" id="ref-for-idl-DOMString"><c- b>DOMString</c-></a>> <dfn class="dfn-paneled idl-code" data-dfn-for="Keyboard/lock(keyCodes), Keyboard/lock()" data-dfn-type="argument" data-export id="dom-keyboard-lock-keycodes-keycodes"><code><c- g>keyCodes</c-></code></dfn> = []);
  <c- b>void</c-> <dfn class="dfn-paneled idl-code" data-dfn-for="Keyboard" data-dfn-type="method" data-export data-lt="unlock()" id="dom-keyboard-unlock"><code><c- g>unlock</c-></code></dfn>();
};
</pre>
   <div id="keyboard-idl">
    <p>The keyboard object has <dfn class="dfn-paneled" data-dfn-for="Keyboard" data-dfn-type="dfn" data-noexport id="keyboard-enable-keyboard-lock">enable keyboard lock</dfn>, which is a
		boolean that is set to true when Keyboard Lock is enabled.
		By default, this is set to false.</p>
    <p>The keyboard object has <dfn class="dfn-paneled" data-dfn-for="Keyboard" data-dfn-type="dfn" data-noexport id="keyboard-reserved-key-codes">reserved key codes</dfn>, which is a
		set of DOMStrings, each of which is a valid <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#key-code-attribute-value" id="ref-for-key-code-attribute-value">key code attribute value</a> as defined in <a data-link-type="biblio" href="#biblio-uievents-code">[UIEvents-Code]</a>.
		By default this set is empty (which would capture all keys
		if <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock">enable keyboard lock</a> was enabled).</p>
    <p>The keyboard object has a <dfn class="dfn-paneled" data-dfn-for="Keyboard" data-dfn-type="dfn" data-noexport id="keyboard-keyboard-lock-task-queue">keyboard lock task queue</dfn> which is
		initialized to the result of <a data-link-type="dfn" href="https://html.spec.whatwg.org/multipage/infrastructure.html#starting-a-new-parallel-queue" id="ref-for-starting-a-new-parallel-queue">starting a new parallel queue</a>.</p>
    <div class="algorithm" data-algorithm="keyboard-lock">
     <h4 class="heading settled" data-level="2.2.1" id="h-keyboard-lock"><span class="secno">2.2.1. </span><span class="content"><dfn data-dfn-for="Keyboard" data-dfn-type="dfn" data-noexport id="keyboard-lock">lock()<a class="self-link" href="#keyboard-lock"></a></dfn></span><a class="self-link" href="#h-keyboard-lock"></a></h4>
     <p>When <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock">lock()</a></code> is called, the user agent must
			run the following steps:</p>
     <ol>
      <li data-md>
       <p>Let <var>p</var> be a new <a data-link-type="dfn" href="http://tc39.github.io/ecma262/#sec-promise-objects" id="ref-for-sec-promise-objects">Promise</a>.</p>
      <li data-md>
       <p>If not currently executing in the currently active <a data-link-type="dfn" href="https://html.spec.whatwg.org/#top-level-browsing-context" id="ref-for-top-level-browsing-context">top-level browsing context</a>, then</p>
       <ol>
        <li data-md>
         <p>Reject <var>p</var> with an "<code class="idl"><a data-link-type="idl" href="https://heycam.github.io/webidl/#invalidstateerror" id="ref-for-invalidstateerror">InvalidStateError</a></code>" <code class="idl"><a data-link-type="idl" href="https://heycam.github.io/webidl/#idl-DOMException" id="ref-for-idl-DOMException">DOMException</a></code>.</p>
       </ol>
      <li data-md>
       <p><a data-link-type="dfn" href="https://html.spec.whatwg.org/multipage/infrastructure.html#enqueue-the-following-steps" id="ref-for-enqueue-the-following-steps">Enqueue the following steps</a> to the <a data-link-type="dfn" href="#keyboard-keyboard-lock-task-queue" id="ref-for-keyboard-keyboard-lock-task-queue">keyboard lock task queue</a>:</p>
       <ol>
        <li data-md>
         <p>Reset <a data-link-type="dfn" href="#keyboard-reserved-key-codes" id="ref-for-keyboard-reserved-key-codes">reserved key codes</a> to be an empty set.</p>
        <li data-md>
         <p>If the optional <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock-keycodes-keycodes" id="ref-for-dom-keyboard-lock-keycodes-keycodes">keyCodes</a></code> argument is present, run the
following substeps:</p>
         <ol>
          <li data-md>
           <p><a data-link-type="dfn" href="https://infra.spec.whatwg.org/#list-iterate" id="ref-for-list-iterate">For each</a> string <var>key</var> in <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock-keycodes-keycodes" id="ref-for-dom-keyboard-lock-keycodes-keycodes①">keyCodes</a></code>:</p>
           <ol>
            <li data-md>
             <p>If <var>key</var> is not a valid <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#key-code-attribute-value" id="ref-for-key-code-attribute-value①">key code attribute value</a>, then</p>
             <ol>
              <li data-md>
               <p>Set <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock①">enable keyboard lock</a> to be false.</p>
              <li data-md>
               <p>Reject <var>p</var> with an "<code class="idl"><a data-link-type="idl" href="https://heycam.github.io/webidl/#invalidaccesserror" id="ref-for-invalidaccesserror">InvalidAccessError</a></code>" <code class="idl"><a data-link-type="idl" href="https://heycam.github.io/webidl/#idl-DOMException" id="ref-for-idl-DOMException①">DOMException</a></code>.</p>
             </ol>
            <li data-md>
             <p><a data-link-type="dfn" href="https://infra.spec.whatwg.org/#set-append" id="ref-for-set-append">Append</a> <var>key</var> to <a data-link-type="dfn" href="#keyboard-reserved-key-codes" id="ref-for-keyboard-reserved-key-codes①">reserved key codes</a>.</p>
           </ol>
         </ol>
        <li data-md>
         <p>If <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock②">enable keyboard lock</a> is currently false, run the following
substeps:</p>
         <ol>
          <li data-md>
           <p>Optionally, <a data-link-type="dfn" href="#register-a-system-key-press-handler" id="ref-for-register-a-system-key-press-handler">register a system key press handler</a>.</p>
          <li data-md>
           <p>Set <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock③">enable keyboard lock</a> to be true.</p>
         </ol>
        <li data-md>
         <p>If there is a pending <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock①">lock()</a></code> task in the <a data-link-type="dfn" href="#keyboard-keyboard-lock-task-queue" id="ref-for-keyboard-keyboard-lock-task-queue①">keyboard lock task queue</a>, then</p>
         <ol>
          <li data-md>
           <p>Set <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock④">enable keyboard lock</a> to be false.</p>
          <li data-md>
           <p>Reject the <var>p</var> with an "<code class="idl"><a data-link-type="idl" href="https://heycam.github.io/webidl/#aborterror" id="ref-for-aborterror">AbortError</a></code>" DOMException.</p>
         </ol>
        <li data-md>
         <p>Resolve <var>p</var>.</p>
       </ol>
      <li data-md>
       <p>Return <var>p</var>.</p>
     </ol>
     <div></div>
     <p class="note" role="note"><span>Note:</span> If <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock②">lock()</a></code> is called multiple times without an
			intervening call to <code class="idl"><a data-link-type="idl" href="#dom-keyboard-unlock" id="ref-for-dom-keyboard-unlock">unlock()</a></code>, then only the <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock-keycodes-keycodes" id="ref-for-dom-keyboard-lock-keycodes-keycodes②">keyCodes</a></code> specified in the last request call will be in effect.
			If a second call to <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock③">lock()</a></code> is made before the first one has finished,
			then the first one will be rejected with "<code class="idl"><a data-link-type="idl" href="https://heycam.github.io/webidl/#aborterror" id="ref-for-aborterror①">AbortError</a></code>".</p>
     <div class="example" id="example-3c1370ba">
      <a class="self-link" href="#example-3c1370ba"></a> To capture all keys, simply call <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock④">lock()</a></code> with no arguments: 
<pre>navigator.keyboard.lock();
</pre>
     </div>
     <div class="example" id="example-5c32e45b">
      <a class="self-link" href="#example-5c32e45b"></a> To capture the "W", "A", "S", and "D" keys, call <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock⑤">lock()</a></code> with
			a list that contains the <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#key-code-attribute-value" id="ref-for-key-code-attribute-value②">key code attribute value</a> for each of these keys: 
<pre>navigator.keyboard.lock(["KeyW", "KeyA", "KeyS", "KeyD"]);
</pre>
      <p>This will capture these keys regardless of which modifiers are used with the
			key press. Assuming a standard US QWERTY layout, registering <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#code-keyw" id="ref-for-code-keyw">KeyW</a> will
			ensure that "W", Shift+"W", Control+"W", Control+Shift+"W", and all other key
			modifier combinations with "W" will be sent to the app. Similarly for <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#code-keya" id="ref-for-code-keya">KeyA</a>, <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#code-keys" id="ref-for-code-keys">KeyS</a> and <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#code-keyd" id="ref-for-code-keyd">KeyD</a>.</p>
     </div>
     <div class="example" id="example-025aab28">
      <a class="self-link" href="#example-025aab28"></a> Note that requesting a key is not a guarantee that all modified versions will
			be made available to the app. As an example, consider <a data-link-type="dfn" href="http://www.w3.org/TR/uievents-code/#code-delete" id="ref-for-code-delete">Delete</a> 
<pre>navigator.keyboard.lock(["Delete"]);
</pre>
      <p>While this will make most Delete key presses available (e.g., Shift+Delete,
			Control+Delete, Shift+Control+Delete), on Windows it will not make available
			the “secure attention sequence” Control+Alt+Delete.</p>
     </div>
    </div>
    <div class="algorithm" data-algorithm="keyboard-unlock">
     <h4 class="heading settled" data-level="2.2.2" id="h-keyboard-unlock"><span class="secno">2.2.2. </span><span class="content"><dfn data-dfn-for="Keyboard" data-dfn-type="dfn" data-noexport id="keyboard-unlock">unlock()<a class="self-link" href="#keyboard-unlock"></a></dfn></span><a class="self-link" href="#h-keyboard-unlock"></a></h4>
     <p>When <code class="idl"><a data-link-type="idl" href="#dom-keyboard-unlock" id="ref-for-dom-keyboard-unlock①">unlock()</a></code> is called, the user agent must
			run the following steps:</p>
     <ol>
      <li data-md>
       <p><a data-link-type="dfn" href="https://html.spec.whatwg.org/multipage/infrastructure.html#enqueue-the-following-steps" id="ref-for-enqueue-the-following-steps①">Enqueue the following steps</a> to the <a data-link-type="dfn" href="#keyboard-keyboard-lock-task-queue" id="ref-for-keyboard-keyboard-lock-task-queue②">keyboard lock task queue</a>:</p>
       <ol>
        <li data-md>
         <p>If <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock⑤">enable keyboard lock</a> is true, then run the following substeps:</p>
         <ol>
          <li data-md>
           <p><a data-link-type="dfn" href="#unregister-the-system-key-press-handler" id="ref-for-unregister-the-system-key-press-handler">Unregister the system key press handler</a>.</p>
          <li data-md>
           <p>Set <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock⑥">enable keyboard lock</a> to be false.</p>
          <li data-md>
           <p>Reset <a data-link-type="dfn" href="#keyboard-reserved-key-codes" id="ref-for-keyboard-reserved-key-codes②">reserved key codes</a> to be an empty sequence.</p>
         </ol>
       </ol>
     </ol>
     <div></div>
     <p class="note" role="note"><span>Note:</span> When a document is closed, the user agent MUST implicitly call <code class="idl"><a data-link-type="idl" href="#dom-keyboard-unlock" id="ref-for-dom-keyboard-unlock②">unlock()</a></code> so that the [system key press handler=] (if any) is
			unregistered.</p>
    </div>
   </div>
   <h2 class="heading settled" data-level="3" id="handling-events"><span class="secno">3. </span><span class="content">Handling Keyboard Key Presses</span><a class="self-link" href="#handling-events"></a></h2>
   <h3 class="heading settled" data-level="3.1" id="key-press-handler"><span class="secno">3.1. </span><span class="content">System Key Press Handler</span><a class="self-link" href="#key-press-handler"></a></h3>
    A <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="system-key-press-handler">system key press handler</dfn> is an platform-specific handler
		that can be used to filter keys at the platform level. Since
		Keyboard Lock feature is intended to provide access to key
		presses that are not normally made available to the browser (for
		example, Cmd/Alt-Tab), most platforms will require a special handler
		to be set up. 
   <p>The <a data-link-type="dfn" href="#system-key-press-handler" id="ref-for-system-key-press-handler">system key press handler</a> must have the following properties:</p>
   <ul>
    <li data-md>
     <p>It must process key presses before any user agent keyboard shortcuts
are handled.</p>
    <li data-md>
     <p>Wherever possible, it should process key presses before any system
keyboard shortcuts are processed.</p>
   </ul>
   <h4 class="heading settled" data-level="3.1.1" id="registering"><span class="secno">3.1.1. </span><span class="content">Registering</span><a class="self-link" href="#registering"></a></h4>
   <p>To <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="register-a-system-key-press-handler">register a system key press handler</dfn>, the user agent
			will need to follow the platform-specific steps to add a low-level
			hook that will be called whenever the platform begins to process a
			new key press.</p>
   <p>The exact process for adding a <a data-link-type="dfn" href="#system-key-press-handler" id="ref-for-system-key-press-handler①">system key press handler</a> varies
			from platform to platform. For examples of how to register a
			low-level hook to process key presses on common platforms, see <a data-link-type="biblio" href="#biblio-lowlevelkeyboardproc">[LowLevelKeyboardProc]</a> for Windows, <a data-link-type="biblio" href="#biblio-quartzeventservices">[QuartzEventServices]</a> for
			Mac OS X and <a data-link-type="biblio" href="#biblio-grabkeyboard">[GrabKeyboard]</a> for X Windows.</p>
   <p class="note" role="note"><span>Note:</span> If the user agent already has a key press handler registered
			for another purpose, then it can optionally extend that handler to
			support the Keyboard Lock feature (assuming it meets the
			requirements mentioned above).</p>
   <h4 class="heading settled" data-level="3.1.2" id="unregistering"><span class="secno">3.1.2. </span><span class="content">Unregistering</span><a class="self-link" href="#unregistering"></a></h4>
   <p>To <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="unregister-the-system-key-press-handler">unregister the system key press handler</dfn>, the user
			agent will need to follow the platform-specific steps to remove the
			(previously added) low-level hook for processing new key press.</p>
   <p>As with registering system key press handlers, the process for
			unregistering system key press handlers is also platform-specific.
			See the references listed in <a href="#registering">§ 3.1.1 Registering</a> for more details and
			examples.</p>
   <h3 class="heading settled" data-level="3.2" id="handling-keyboard-events"><span class="secno">3.2. </span><span class="content">Handling Keyboard Events</span><a class="self-link" href="#handling-keyboard-events"></a></h3>
   <p>In response to the user pressing a key, if a <a data-link-type="dfn" href="#system-key-press-handler" id="ref-for-system-key-press-handler②">system key press handler</a> has been <a data-link-type="dfn" href="#register-a-system-key-press-handler" id="ref-for-register-a-system-key-press-handler①">registered</a>,
		it should run the following steps:</p>
   <ol>
    <li data-md>
     <p>Let <var>isFullscreen</var> be set to true if the <a data-link-type="dfn" href="https://fullscreen.spec.whatwg.org/#fullscreen-element" id="ref-for-fullscreen-element">fullscreen element</a> of the <a data-link-type="dfn" href="https://html.spec.whatwg.org/#currently-focused-area-of-a-top-level-browsing-context" id="ref-for-currently-focused-area-of-a-top-level-browsing-context">currently focused area of a top-level browsing context</a> is non-null
(see <a data-link-type="biblio" href="#biblio-fullscreen">[Fullscreen]</a>).</p>
     <p class="note" role="note"><span>Note:</span> The <a data-link-type="dfn" href="https://fullscreen.spec.whatwg.org/#fullscreen-element" id="ref-for-fullscreen-element①">fullscreen element</a> would not have focus, for example, if
there was a system dialog being displayed with focus.</p>
    <li data-md>
     <p>If <var>isFullscreen</var> and <a data-link-type="dfn" href="#keyboard-enable-keyboard-lock" id="ref-for-keyboard-enable-keyboard-lock⑦">enable keyboard lock</a> are all set
to true, then run the following substeps:</p>
     <ol>
      <li data-md>
       <p>Let <var>keyEvent</var> be the key event for the new key press.</p>
      <li data-md>
       <p>Let <var>code</var> be the value of the <code class="idl"><a data-link-type="idl" href="https://www.w3.org/TR/uievents/#dom-keyboardevent-code" id="ref-for-dom-keyboardevent-code">code</a></code> attribute of <var>keyEvent</var>.</p>
      <li data-md>
       <p>If <a data-link-type="dfn" href="#keyboard-reserved-key-codes" id="ref-for-keyboard-reserved-key-codes③">reserved key codes</a> is empty or if <var>code</var> is listed in <a data-link-type="dfn" href="#keyboard-reserved-key-codes" id="ref-for-keyboard-reserved-key-codes④">reserved key codes</a>, then run the following substeps:</p>
       <ol>
        <li data-md>
         <p>If <var>code</var> is equal to "Escape", then run the following
substeps:</p>
         <ol>
          <li data-md>
           <p>Optionally overlay a message on the screen telling the
user that they can Hold the Escape key to exit from
fullscreen.</p>
          <li data-md>
           <p>If the key is held for 2 seconds, then exit from the
keyboard handler and pass the key on to the user agent
for normal processing (which will exit fullscreen
(and pointer lock, if active)).</p>
         </ol>
        <li data-md>
         <p>Dispatch <var>keyEvent</var> directly to the fullsceen document or element,
bypassing any normal user agent processing.</p>
       </ol>
      <li data-md>
       <p>Else, handle the key event as it normally would be handled,
either by dispatching a key event or performing the
usual keyboard shortcut action.</p>
     </ol>
   </ol>
   <p class="note" role="note"><span>Note:</span> This API operates on a "best effort" basis.
		It is not required that a conforming implementation be able to
		override the OS default behaviour for every possible key combination.
		Specifically, most platforms have a “secure attention sequence” (e.g.,
		Ctrl-Alt-Del on Windows) that applications cannot override; this
		specification does not supersede that.</p>
   <p class="note" role="note"><span>Note:</span> When implementing this API, user agents should take care not to change
		the order in which keyboard events are dispatched to the page. Keys that are
		included in the set of <a data-link-type="dfn" href="#keyboard-reserved-key-codes" id="ref-for-keyboard-reserved-key-codes⑤">reserved key codes</a> must be dispatched in the same
		relative order that they would have been sent had they not been included in the
		set.</p>
   <h2 class="heading settled" data-level="4" id="interactions"><span class="secno">4. </span><span class="content">Intergration With Other Web Platform APIs</span><a class="self-link" href="#interactions"></a></h2>
   <p><a data-link-type="biblio" href="#biblio-fullscreen">[Fullscreen]</a> and <a data-link-type="biblio" href="#biblio-pointerlock">[PointerLock]</a> are APIs that allow the page to temporarily take
	control of part of the user’s experience (screen and mouse cursor, respectively).
	Because of the concern for abuse of these features, they provide an "escape" or
	"unlock" gesture that the user can rely on to exit those features. By default,
	this gesture is pressing the Escape key, which is one of the keys that can be
	captured by this API.</p>
   <h3 class="heading settled" data-level="4.1" id="escape-key"><span class="secno">4.1. </span><span class="content">Special Considerations with the Escape Key</span><a class="self-link" href="#escape-key"></a></h3>
   <p>Because of the special actions associated with the Escape key, when the <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock⑥">lock()</a></code> request includes the Escape key, the user agent may need to make additional
		changes to the UX to account for the changed behavior.</p>
   <p>For example, if the user agent shows a user message "Press ESC to exit fullscreen"
		when Javascript-initiated fullscreen is activated, then that message will need to
		be updated when keyboard lock is in effect to read "Press and hold ESC to exit
		fullscreen".</p>
   <p>If keyboard lock is activated after fullscreen is already in effect, then the user
		my see multiple messages about how to exit fullscreen.
		For this reason, we recommend that developers call <code class="idl"><a data-link-type="idl" href="#dom-keyboard-lock" id="ref-for-dom-keyboard-lock⑦">lock()</a></code> before they enter
		fullscreen:</p>
<pre>navigator.keyboard.lock();
document.documentElement.requestFullscreen();
</pre>
   <p>A similar concern with multiple user messages exists when exiting keyboard lock and
		fullscreen, so it is recommended to call them in the reverse order:</p>
<pre>document.exitFullscreen();
navigator.keyboard.unlock();
</pre>
   <p>In general, developers should only include the Escape key in the set of locked
		keys if they actually have need for that key. And it is recommended that, if the
		Escape key is locked, the developer should maintain its primary meaning of
		allowing the user to exit their current state.</p>
   <h3 class="heading settled" data-level="4.2" id="fullscreen-considerations"><span class="secno">4.2. </span><span class="content">Fullscreen Considerations</span><a class="self-link" href="#fullscreen-considerations"></a></h3>
   <p>There are two different types of fullscreen available in modern user agents:
		JavaScript-initiated fullscreen (via the <a data-link-type="biblio" href="#biblio-fullscreen">[Fullscreen]</a> API) and
		user-initiated fullscreen (when the user enters fullscreen using a keyboard
		shortcut). The user-initiated fullscreen is often referred to as "F11"
		fullscreen since that is a common key shortcut used to enter and exit
		fullscreen mode.</p>
   <p>F11 fullscreen and JavaScript (JS) fullscreen do not behave the same way.
		When a user enters F11 fullscreen, they can only exit it via the same
		keyboard shortcut that they used to enter it -- the exitFullscreen()
		function will not work in this case. In addition, fullscreen events that are
		normally fired for JS fullscreen are not sent for F11 fullscreen.</p>
   <p>Because of these differences (and because there is no standard shortcut
		for F11 fullscreen), the Keyboard Lock API is only valid when the
		a JavaScript-initiated fullscreen is active. During F11 fullscreen, no
		Keyboard Lock processing of keyboard events will take place.</p>
   <h2 class="heading settled" data-level="5" id="pointerlock-considerations"><span class="secno">5. </span><span class="content">Pointer Lock Considerations</span><a class="self-link" href="#pointerlock-considerations"></a></h2>
   <p>Other than the UX changes noted earlier, there are no changes to the operation
		of Pointer Lock.</p>
   <p>When Pointer Lock is enabled outside of fullscreen, then Keyboard Lock cannot
		be enabled.</p>
   <p>When Pointer Lock, Keyboard Lock and Fullscreen are all enabled, then the behavior
		is unchanged unless Keyboard Lock includes the Escape key. In that case, the
		only chages are to the UX (as noted above).</p>
   <h2 class="heading settled" data-level="6" id="mobile"><span class="secno">6. </span><span class="content">Mobile Device Considerations</span><a class="self-link" href="#mobile"></a></h2>
   <p>Since this is a keyboard-focused API and mobile devices do not commonly
	have physical keyboards, this API will not typically be present or
	supported on mobile devices.</p>
   <p>However, mobile devices may choose to support this API if it makes sense to
	do so when a physical keyboard is connected.</p>
   <h2 class="heading settled" data-level="7" id="security"><span class="secno">7. </span><span class="content">Security Considerations</span><a class="self-link" href="#security"></a></h2>
   <p>One concern with this API is that it could be used to grab all of the keys
	and (in conjunction with the <a data-link-type="biblio" href="#biblio-fullscreen">[Fullscreen]</a> and <a data-link-type="biblio" href="#biblio-pointerlock">[PointerLock]</a> API) prevent
	the user from exiting the web page.</p>
   <p>To prevent this, the user agent MUST provide a way for the user to exit from
	keyboard lock even if all of the keys are requested by the API.</p>
   <p>This specification requires support for allowing a long (more than 2 second) Escape
	key press to trigger an exit from Keyboard Lock. In addition, user agents may choose
	to also provide alternate ways to exit Keyboard Lock.</p>
   <h2 class="heading settled" data-level="8" id="privacy"><span class="secno">8. </span><span class="content">Privacy Considerations</span><a class="self-link" href="#privacy"></a></h2>
   <p>Not applicable. This API does not use or reveal any personal information
	about the current user.</p>
   <h2 class="heading settled" data-level="9" id="acknowledgements-contributors"><span class="secno">9. </span><span class="content">Acknowledgements</span><a class="self-link" href="#acknowledgements-contributors"></a></h2>
   <p>Thanks to the following people for the discussions that lead
	to the creation of this proposal:</p>
   <p>Jon Dahlke (Google),
	Joe Downing (Google)</p>
  </main>
  <div data-fill-with="conformance">
   <h2 class="no-ref no-num heading settled" id="conformance"><span class="content">Conformance</span><a class="self-link" href="#conformance"></a></h2>
   <h3 class="no-ref no-num heading settled" id="conventions"><span class="content">Document conventions</span><a class="self-link" href="#conventions"></a></h3>
   <p>Conformance requirements are expressed with a combination of
    descriptive assertions and RFC 2119 terminology. The key words “MUST”,
    “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”,
    “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this
    document are to be interpreted as described in RFC 2119.
    However, for readability, these words do not appear in all uppercase
    letters in this specification. </p>
   <p>All of the text of this specification is normative except sections
    explicitly marked as non-normative, examples, and notes. <a data-link-type="biblio" href="#biblio-rfc2119">[RFC2119]</a></p>
   <p>Examples in this specification are introduced with the words “for example”
    or are set apart from the normative text with <code>class="example"</code>,
    like this: </p>
   <div class="example" id="example-ae2b6bc0">
    <a class="self-link" href="#example-ae2b6bc0"></a> 
    <p>This is an example of an informative example.</p>
   </div>
   <p>Informative notes begin with the word “Note” and are set apart from the
    normative text with <code>class="note"</code>, like this: </p>
   <p class="note" role="note">Note, this is an informative note.</p>
   <h3 class="no-ref no-num heading settled" id="conformant-algorithms"><span class="content">Conformant Algorithms</span><a class="self-link" href="#conformant-algorithms"></a></h3>
   <p>Requirements phrased in the imperative as part of algorithms (such as
    "strip any leading space characters" or "return false and abort these
    steps") are to be interpreted with the meaning of the key word ("must",
    "should", "may", etc) used in introducing the algorithm.</p>
   <p>Conformance requirements phrased as algorithms or specific steps can be
    implemented in any manner, so long as the end result is equivalent. In
    particular, the algorithms defined in this specification are intended to
    be easy to understand and are not intended to be performant. Implementers
    are encouraged to optimize.</p>
  </div>
  <p id="back-to-top" role="navigation"><a href="#toc"><abbr title="Back to top">↑</abbr></a></p>
  . 
<script src="https://www.w3.org/scripts/TR/2016/fixup.js"></script>
  <h2 class="no-num no-ref heading settled" id="index"><span class="content">Index</span><a class="self-link" href="#index"></a></h2>
  <h3 class="no-num no-ref heading settled" id="index-defined-here"><span class="content">Terms defined by this specification</span><a class="self-link" href="#index-defined-here"></a></h3>
  <ul class="index">
   <li><a href="#keyboard-enable-keyboard-lock">enable keyboard lock</a><span>, in §2.2</span>
   <li>
    keyboard
    <ul>
     <li><a href="#dom-navigator-keyboard">attribute for Navigator</a><span>, in §2.1</span>
     <li><a href="#navigator-keyboard">dfn for Navigator</a><span>, in §2.1.1</span>
    </ul>
   <li><a href="#keyboard">Keyboard</a><span>, in §2.2</span>
   <li><a href="#keyboard-keyboard-lock-task-queue">keyboard lock task queue</a><span>, in §2.2</span>
   <li>
    lock()
    <ul>
     <li><a href="#keyboard-lock">dfn for Keyboard</a><span>, in §2.2.1</span>
     <li><a href="#dom-keyboard-lock">method for Keyboard</a><span>, in §2.2</span>
    </ul>
   <li><a href="#dom-keyboard-lock">lock(keyCodes)</a><span>, in §2.2</span>
   <li><a href="#register-a-system-key-press-handler">register a system key press handler</a><span>, in §3.1.1</span>
   <li><a href="#keyboard-reserved-key-codes">reserved key codes</a><span>, in §2.2</span>
   <li><a href="#system-key-press-handler">system key press handler</a><span>, in §3.1</span>
   <li>
    unlock()
    <ul>
     <li><a href="#keyboard-unlock">dfn for Keyboard</a><span>, in §2.2.2</span>
     <li><a href="#dom-keyboard-unlock">method for Keyboard</a><span>, in §2.2</span>
    </ul>
   <li><a href="#unregister-the-system-key-press-handler">unregister the system key press handler</a><span>, in §3.1.2</span>
  </ul>
  <aside class="dfn-panel" data-for="term-for-sec-promise-objects">
   <a href="http://tc39.github.io/ecma262/#sec-promise-objects">http://tc39.github.io/ecma262/#sec-promise-objects</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-sec-promise-objects">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-fullscreen-element">
   <a href="https://fullscreen.spec.whatwg.org/#fullscreen-element">https://fullscreen.spec.whatwg.org/#fullscreen-element</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-fullscreen-element">3.2. Handling Keyboard Events</a> <a href="#ref-for-fullscreen-element①">(2)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-navigator">
   <a href="https://html.spec.whatwg.org/multipage/system-state.html#navigator">https://html.spec.whatwg.org/multipage/system-state.html#navigator</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-navigator">2.1. Navigator Interface</a>
    <li><a href="#ref-for-navigator①">2.1.1. keyboard</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-currently-focused-area-of-a-top-level-browsing-context">
   <a href="https://html.spec.whatwg.org/#currently-focused-area-of-a-top-level-browsing-context">https://html.spec.whatwg.org/#currently-focused-area-of-a-top-level-browsing-context</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-currently-focused-area-of-a-top-level-browsing-context">3.2. Handling Keyboard Events</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-enqueue-the-following-steps">
   <a href="https://html.spec.whatwg.org/multipage/infrastructure.html#enqueue-the-following-steps">https://html.spec.whatwg.org/multipage/infrastructure.html#enqueue-the-following-steps</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-enqueue-the-following-steps">2.2.1. lock()</a>
    <li><a href="#ref-for-enqueue-the-following-steps①">2.2.2. unlock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-starting-a-new-parallel-queue">
   <a href="https://html.spec.whatwg.org/multipage/infrastructure.html#starting-a-new-parallel-queue">https://html.spec.whatwg.org/multipage/infrastructure.html#starting-a-new-parallel-queue</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-starting-a-new-parallel-queue">2.2. Keyboard Interface</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-top-level-browsing-context">
   <a href="https://html.spec.whatwg.org/#top-level-browsing-context">https://html.spec.whatwg.org/#top-level-browsing-context</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-top-level-browsing-context">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-set-append">
   <a href="https://infra.spec.whatwg.org/#set-append">https://infra.spec.whatwg.org/#set-append</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-set-append">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-list-iterate">
   <a href="https://infra.spec.whatwg.org/#list-iterate">https://infra.spec.whatwg.org/#list-iterate</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-list-iterate">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-dom-keyboardevent-code">
   <a href="https://www.w3.org/TR/uievents/#dom-keyboardevent-code">https://www.w3.org/TR/uievents/#dom-keyboardevent-code</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-dom-keyboardevent-code">3.2. Handling Keyboard Events</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-code-delete">
   <a href="http://www.w3.org/TR/uievents-code/#code-delete">http://www.w3.org/TR/uievents-code/#code-delete</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-code-delete">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-key-code-attribute-value">
   <a href="http://www.w3.org/TR/uievents-code/#key-code-attribute-value">http://www.w3.org/TR/uievents-code/#key-code-attribute-value</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-key-code-attribute-value">2.2. Keyboard Interface</a>
    <li><a href="#ref-for-key-code-attribute-value①">2.2.1. lock()</a> <a href="#ref-for-key-code-attribute-value②">(2)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-code-keya">
   <a href="http://www.w3.org/TR/uievents-code/#code-keya">http://www.w3.org/TR/uievents-code/#code-keya</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-code-keya">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-code-keyd">
   <a href="http://www.w3.org/TR/uievents-code/#code-keyd">http://www.w3.org/TR/uievents-code/#code-keyd</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-code-keyd">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-code-keys">
   <a href="http://www.w3.org/TR/uievents-code/#code-keys">http://www.w3.org/TR/uievents-code/#code-keys</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-code-keys">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-code-keyw">
   <a href="http://www.w3.org/TR/uievents-code/#code-keyw">http://www.w3.org/TR/uievents-code/#code-keyw</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-code-keyw">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-aborterror">
   <a href="https://heycam.github.io/webidl/#aborterror">https://heycam.github.io/webidl/#aborterror</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-aborterror">2.2.1. lock()</a> <a href="#ref-for-aborterror①">(2)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-idl-DOMException">
   <a href="https://heycam.github.io/webidl/#idl-DOMException">https://heycam.github.io/webidl/#idl-DOMException</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-idl-DOMException">2.2.1. lock()</a> <a href="#ref-for-idl-DOMException①">(2)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-idl-DOMString">
   <a href="https://heycam.github.io/webidl/#idl-DOMString">https://heycam.github.io/webidl/#idl-DOMString</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-idl-DOMString">2.2. Keyboard Interface</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-Exposed">
   <a href="https://heycam.github.io/webidl/#Exposed">https://heycam.github.io/webidl/#Exposed</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-Exposed">2.2. Keyboard Interface</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-invalidaccesserror">
   <a href="https://heycam.github.io/webidl/#invalidaccesserror">https://heycam.github.io/webidl/#invalidaccesserror</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-invalidaccesserror">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-invalidstateerror">
   <a href="https://heycam.github.io/webidl/#invalidstateerror">https://heycam.github.io/webidl/#invalidstateerror</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-invalidstateerror">2.2.1. lock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-SameObject">
   <a href="https://heycam.github.io/webidl/#SameObject">https://heycam.github.io/webidl/#SameObject</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-SameObject">2.1. Navigator Interface</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="term-for-SecureContext">
   <a href="https://heycam.github.io/webidl/#SecureContext">https://heycam.github.io/webidl/#SecureContext</a><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-SecureContext">2.1. Navigator Interface</a>
    <li><a href="#ref-for-SecureContext①">2.2. Keyboard Interface</a>
   </ul>
  </aside>
  <h3 class="no-num no-ref heading settled" id="index-defined-elsewhere"><span class="content">Terms defined by reference</span><a class="self-link" href="#index-defined-elsewhere"></a></h3>
  <ul class="index">
   <li>
    <a data-link-type="biblio">[ECMASCRIPT]</a> defines the following terms:
    <ul>
     <li><span class="dfn-paneled" id="term-for-sec-promise-objects" style="color:initial">promise</span>
    </ul>
   <li>
    <a data-link-type="biblio">[Fullscreen]</a> defines the following terms:
    <ul>
     <li><span class="dfn-paneled" id="term-for-fullscreen-element" style="color:initial">fullscreen element</span>
    </ul>
   <li>
    <a data-link-type="biblio">[HTML]</a> defines the following terms:
    <ul>
     <li><span class="dfn-paneled" id="term-for-navigator" style="color:initial">Navigator</span>
     <li><span class="dfn-paneled" id="term-for-currently-focused-area-of-a-top-level-browsing-context" style="color:initial">currently focused area of a top-level browsing context</span>
     <li><span class="dfn-paneled" id="term-for-enqueue-the-following-steps" style="color:initial">enqueue the following steps</span>
     <li><span class="dfn-paneled" id="term-for-starting-a-new-parallel-queue" style="color:initial">starting a new parallel queue</span>
     <li><span class="dfn-paneled" id="term-for-top-level-browsing-context" style="color:initial">top-level browsing context</span>
    </ul>
   <li>
    <a data-link-type="biblio">[INFRA]</a> defines the following terms:
    <ul>
     <li><span class="dfn-paneled" id="term-for-set-append" style="color:initial">append</span>
     <li><span class="dfn-paneled" id="term-for-list-iterate" style="color:initial">for each</span>
    </ul>
   <li>
    <a data-link-type="biblio">[uievents]</a> defines the following terms:
    <ul>
     <li><span class="dfn-paneled" id="term-for-dom-keyboardevent-code" style="color:initial">code</span>
    </ul>
   <li>
    <a data-link-type="biblio">[UIEvents-Code]</a> defines the following terms:
    <ul>
     <li><span class="dfn-paneled" id="term-for-code-delete" style="color:initial">delete</span>
     <li><span class="dfn-paneled" id="term-for-key-code-attribute-value" style="color:initial">key code attribute value</span>
     <li><span class="dfn-paneled" id="term-for-code-keya" style="color:initial">keya</span>
     <li><span class="dfn-paneled" id="term-for-code-keyd" style="color:initial">keyd</span>
     <li><span class="dfn-paneled" id="term-for-code-keys" style="color:initial">keys</span>
     <li><span class="dfn-paneled" id="term-for-code-keyw" style="color:initial">keyw</span>
    </ul>
   <li>
    <a data-link-type="biblio">[WebIDL]</a> defines the following terms:
    <ul>
     <li><span class="dfn-paneled" id="term-for-aborterror" style="color:initial">AbortError</span>
     <li><span class="dfn-paneled" id="term-for-idl-DOMException" style="color:initial">DOMException</span>
     <li><span class="dfn-paneled" id="term-for-idl-DOMString" style="color:initial">DOMString</span>
     <li><span class="dfn-paneled" id="term-for-Exposed" style="color:initial">Exposed</span>
     <li><span class="dfn-paneled" id="term-for-invalidaccesserror" style="color:initial">InvalidAccessError</span>
     <li><span class="dfn-paneled" id="term-for-invalidstateerror" style="color:initial">InvalidStateError</span>
     <li><span class="dfn-paneled" id="term-for-SameObject" style="color:initial">SameObject</span>
     <li><span class="dfn-paneled" id="term-for-SecureContext" style="color:initial">SecureContext</span>
    </ul>
  </ul>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3>
  <dl>
   <dt id="biblio-ecmascript">[ECMASCRIPT]
   <dd><a href="https://tc39.github.io/ecma262/">ECMAScript Language Specification</a>. URL: <a href="https://tc39.github.io/ecma262/">https://tc39.github.io/ecma262/</a>
   <dt id="biblio-fullscreen">[Fullscreen]
   <dd>Philip Jägenstedt. <a href="https://fullscreen.spec.whatwg.org/">Fullscreen API Standard</a>. Living Standard. URL: <a href="https://fullscreen.spec.whatwg.org/">https://fullscreen.spec.whatwg.org/</a>
   <dt id="biblio-html">[HTML]
   <dd>Anne van Kesteren; et al. <a href="https://html.spec.whatwg.org/multipage/">HTML Standard</a>. Living Standard. URL: <a href="https://html.spec.whatwg.org/multipage/">https://html.spec.whatwg.org/multipage/</a>
   <dt id="biblio-infra">[INFRA]
   <dd>Anne van Kesteren; Domenic Denicola. <a href="https://infra.spec.whatwg.org/">Infra Standard</a>. Living Standard. URL: <a href="https://infra.spec.whatwg.org/">https://infra.spec.whatwg.org/</a>
   <dt id="biblio-rfc2119">[RFC2119]
   <dd>S. Bradner. <a href="https://tools.ietf.org/html/rfc2119">Key words for use in RFCs to Indicate Requirement Levels</a>. March 1997. Best Current Practice. URL: <a href="https://tools.ietf.org/html/rfc2119">https://tools.ietf.org/html/rfc2119</a>
   <dt id="biblio-uievents">[UIEVENTS]
   <dd>Gary Kacmarcik; Travis Leithead; Doug Schepers. <a href="https://www.w3.org/TR/uievents/">UI Events</a>. 30 May 2019. WD. URL: <a href="https://www.w3.org/TR/uievents/">https://www.w3.org/TR/uievents/</a>
   <dt id="biblio-uievents-code">[UIEvents-Code]
   <dd>Gary Kacmarcik; Travis Leithead. <a href="https://www.w3.org/TR/uievents-code/">UI Events KeyboardEvent code Values</a>. 1 June 2017. CR. URL: <a href="https://www.w3.org/TR/uievents-code/">https://www.w3.org/TR/uievents-code/</a>
   <dt id="biblio-webidl">[WebIDL]
   <dd>Boris Zbarsky. <a href="https://heycam.github.io/webidl/">Web IDL</a>. 15 December 2016. ED. URL: <a href="https://heycam.github.io/webidl/">https://heycam.github.io/webidl/</a>
  </dl>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-grabkeyboard">[GrabKeyboard]
   <dd><a href="https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#requests:GrabKeyboard">X11 GrabKeyboard API</a>. URL: <a href="https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#requests:GrabKeyboard">https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#requests:GrabKeyboard</a>
   <dt id="biblio-lowlevelkeyboardproc">[LowLevelKeyboardProc]
   <dd><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx">LowLevelKeyboardProc documentation on MSDN</a>. URL: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx">https://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx</a>
   <dt id="biblio-pointerlock">[PointerLock]
   <dd>Vincent Scheib. <a href="https://www.w3.org/TR/pointerlock/">Pointer Lock</a>. 27 October 2016. REC. URL: <a href="https://www.w3.org/TR/pointerlock/">https://www.w3.org/TR/pointerlock/</a>
   <dt id="biblio-quartzeventservices">[QuartzEventServices]
   <dd><a href="https://developer.apple.com/reference/coregraphics/1658572-quartz_event_services">Quartz Event Services</a>. URL: <a href="https://developer.apple.com/reference/coregraphics/1658572-quartz_event_services">https://developer.apple.com/reference/coregraphics/1658572-quartz_event_services</a>
  </dl>
  <h2 class="no-num no-ref heading settled" id="idl-index"><span class="content">IDL Index</span><a class="self-link" href="#idl-index"></a></h2>
<pre class="idl highlight def"><c- b>partial</c-> <c- b>interface</c-> <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/system-state.html#navigator" id="ref-for-navigator②"><c- g>Navigator</c-></a> {
  [<a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#SecureContext" id="ref-for-SecureContext②"><c- g>SecureContext</c-></a>, <a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#SameObject" id="ref-for-SameObject①"><c- g>SameObject</c-></a>] <c- b>readonly</c-> <c- b>attribute</c-> <a class="n" data-link-type="idl-name" href="#keyboard" id="ref-for-keyboard②"><c- n>Keyboard</c-></a> <a data-readonly data-type="Keyboard" href="#dom-navigator-keyboard"><code><c- g>keyboard</c-></code></a>;
};

[<a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#SecureContext" id="ref-for-SecureContext①①"><c- g>SecureContext</c-></a>, <a class="idl-code" data-link-type="extended-attribute" href="https://heycam.github.io/webidl/#Exposed" id="ref-for-Exposed①"><c- g>Exposed</c-></a>=<c- n>Window</c->] <c- b>interface</c-> <a href="#keyboard"><code><c- g>Keyboard</c-></code></a> {
  <c- b>Promise</c->&lt;<c- b>void</c->> <a href="#dom-keyboard-lock"><code><c- g>lock</c-></code></a>(<c- b>optional</c-> <c- b>sequence</c->&lt;<a class="idl-code" data-link-type="interface" href="https://heycam.github.io/webidl/#idl-DOMString" id="ref-for-idl-DOMString①"><c- b>DOMString</c-></a>> <a href="#dom-keyboard-lock-keycodes-keycodes"><code><c- g>keyCodes</c-></code></a> = []);
  <c- b>void</c-> <a href="#dom-keyboard-unlock"><code><c- g>unlock</c-></code></a>();
};

</pre>
  <aside class="dfn-panel" data-for="navigator-keyboard">
   <b><a href="#navigator-keyboard">#navigator-keyboard</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-navigator-keyboard">2.1.1. keyboard</a>
    <li><a href="#ref-for-navigator-keyboard①">2.1. Navigator Interface</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="keyboard">
   <b><a href="#keyboard">#keyboard</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-keyboard">2.1. Navigator Interface</a>
    <li><a href="#ref-for-keyboard①">2.1.1. keyboard</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="dom-keyboard-lock">
   <b><a href="#dom-keyboard-lock">#dom-keyboard-lock</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-dom-keyboard-lock">2.2.1. lock()</a> <a href="#ref-for-dom-keyboard-lock①">(2)</a> <a href="#ref-for-dom-keyboard-lock②">(3)</a> <a href="#ref-for-dom-keyboard-lock③">(4)</a> <a href="#ref-for-dom-keyboard-lock④">(5)</a> <a href="#ref-for-dom-keyboard-lock⑤">(6)</a>
    <li><a href="#ref-for-dom-keyboard-lock⑥">4.1. Special Considerations with the Escape Key</a> <a href="#ref-for-dom-keyboard-lock⑦">(2)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="dom-keyboard-lock-keycodes-keycodes">
   <b><a href="#dom-keyboard-lock-keycodes-keycodes">#dom-keyboard-lock-keycodes-keycodes</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-dom-keyboard-lock-keycodes-keycodes">2.2.1. lock()</a> <a href="#ref-for-dom-keyboard-lock-keycodes-keycodes①">(2)</a> <a href="#ref-for-dom-keyboard-lock-keycodes-keycodes②">(3)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="dom-keyboard-unlock">
   <b><a href="#dom-keyboard-unlock">#dom-keyboard-unlock</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-dom-keyboard-unlock">2.2.1. lock()</a>
    <li><a href="#ref-for-dom-keyboard-unlock①">2.2.2. unlock()</a> <a href="#ref-for-dom-keyboard-unlock②">(2)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="keyboard-enable-keyboard-lock">
   <b><a href="#keyboard-enable-keyboard-lock">#keyboard-enable-keyboard-lock</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-keyboard-enable-keyboard-lock">2.2. Keyboard Interface</a>
    <li><a href="#ref-for-keyboard-enable-keyboard-lock①">2.2.1. lock()</a> <a href="#ref-for-keyboard-enable-keyboard-lock②">(2)</a> <a href="#ref-for-keyboard-enable-keyboard-lock③">(3)</a> <a href="#ref-for-keyboard-enable-keyboard-lock④">(4)</a>
    <li><a href="#ref-for-keyboard-enable-keyboard-lock⑤">2.2.2. unlock()</a> <a href="#ref-for-keyboard-enable-keyboard-lock⑥">(2)</a>
    <li><a href="#ref-for-keyboard-enable-keyboard-lock⑦">3.2. Handling Keyboard Events</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="keyboard-reserved-key-codes">
   <b><a href="#keyboard-reserved-key-codes">#keyboard-reserved-key-codes</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-keyboard-reserved-key-codes">2.2.1. lock()</a> <a href="#ref-for-keyboard-reserved-key-codes①">(2)</a>
    <li><a href="#ref-for-keyboard-reserved-key-codes②">2.2.2. unlock()</a>
    <li><a href="#ref-for-keyboard-reserved-key-codes③">3.2. Handling Keyboard Events</a> <a href="#ref-for-keyboard-reserved-key-codes④">(2)</a> <a href="#ref-for-keyboard-reserved-key-codes⑤">(3)</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="keyboard-keyboard-lock-task-queue">
   <b><a href="#keyboard-keyboard-lock-task-queue">#keyboard-keyboard-lock-task-queue</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-keyboard-keyboard-lock-task-queue">2.2.1. lock()</a> <a href="#ref-for-keyboard-keyboard-lock-task-queue①">(2)</a>
    <li><a href="#ref-for-keyboard-keyboard-lock-task-queue②">2.2.2. unlock()</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="system-key-press-handler">
   <b><a href="#system-key-press-handler">#system-key-press-handler</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-system-key-press-handler">3.1. System Key Press Handler</a>
    <li><a href="#ref-for-system-key-press-handler①">3.1.1. Registering</a>
    <li><a href="#ref-for-system-key-press-handler②">3.2. Handling Keyboard Events</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="register-a-system-key-press-handler">
   <b><a href="#register-a-system-key-press-handler">#register-a-system-key-press-handler</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-register-a-system-key-press-handler">2.2.1. lock()</a>
    <li><a href="#ref-for-register-a-system-key-press-handler①">3.2. Handling Keyboard Events</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="unregister-the-system-key-press-handler">
   <b><a href="#unregister-the-system-key-press-handler">#unregister-the-system-key-press-handler</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-unregister-the-system-key-press-handler">2.2.2. unlock()</a>
   </ul>
  </aside>
<script>/* script-var-click-highlighting */

    document.addEventListener("click", e=>{
        if(e.target.nodeName == "VAR") {
            highlightSameAlgoVars(e.target);
        }
    });
    {
        const indexCounts = new Map();
        const indexNames = new Map();
        function highlightSameAlgoVars(v) {
            // Find the algorithm container.
            let algoContainer = null;
            let searchEl = v;
            while(algoContainer == null && searchEl != document.body) {
                searchEl = searchEl.parentNode;
                if(searchEl.hasAttribute("data-algorithm")) {
                    algoContainer = searchEl;
                }
            }

            // Not highlighting document-global vars,
            // too likely to be unrelated.
            if(algoContainer == null) return;

            const algoName = algoContainer.getAttribute("data-algorithm");
            const varName = getVarName(v);
            const addClass = !v.classList.contains("selected");
            let highlightClass = null;
            if(addClass) {
                const index = chooseHighlightIndex(algoName, varName);
                indexCounts.get(algoName)[index] += 1;
                indexNames.set(algoName+"///"+varName, index);
                highlightClass = nameFromIndex(index);
            } else {
                const index = previousHighlightIndex(algoName, varName);
                indexCounts.get(algoName)[index] -= 1;
                highlightClass = nameFromIndex(index);
            }

            // Find all same-name vars, and toggle their class appropriately.
            for(const el of algoContainer.querySelectorAll("var")) {
                if(getVarName(el) == varName) {
                    el.classList.toggle("selected", addClass);
                    el.classList.toggle(highlightClass, addClass);
                }
            }
        }
        function getVarName(el) {
            return el.textContent.replace(/(\s| )+/, " ").trim();
        }
        function chooseHighlightIndex(algoName, varName) {
            let indexes = null;
            if(indexCounts.has(algoName)) {
                indexes = indexCounts.get(algoName);
            } else {
                // 7 classes right now
                indexes = [0,0,0,0,0,0,0];
                indexCounts.set(algoName, indexes);
            }

            // If the element was recently unclicked,
            // *and* that color is still unclaimed,
            // give it back the same color.
            const lastIndex = previousHighlightIndex(algoName, varName);
            if(indexes[lastIndex] === 0) return lastIndex;

            // Find the earliest index with the lowest count.
            const minCount = Math.min.apply(null, indexes);
            let index = null;
            for(var i = 0; i < indexes.length; i++) {
                if(indexes[i] == minCount) {
                    return i;
                }
            }
        }
        function previousHighlightIndex(algoName, varName) {
            return indexNames.get(algoName+"///"+varName);
        }
        function nameFromIndex(index) {
            return "selected" + index;
        }
    }
    </script>
<script>/* script-dfn-panel */

document.body.addEventListener("click", function(e) {
    var queryAll = function(sel) { return [].slice.call(document.querySelectorAll(sel)); }
    // Find the dfn element or panel, if any, that was clicked on.
    var el = e.target;
    var target;
    var hitALink = false;
    while(el.parentElement) {
        if(el.tagName == "A") {
            // Clicking on a link in a <dfn> shouldn't summon the panel
            hitALink = true;
        }
        if(el.classList.contains("dfn-paneled")) {
            target = "dfn";
            break;
        }
        if(el.classList.contains("dfn-panel")) {
            target = "dfn-panel";
            break;
        }
        el = el.parentElement;
    }
    if(target != "dfn-panel") {
        // Turn off any currently "on" or "activated" panels.
        queryAll(".dfn-panel.on, .dfn-panel.activated").forEach(function(el){
            el.classList.remove("on");
            el.classList.remove("activated");
        });
    }
    if(target == "dfn" && !hitALink) {
        // open the panel
        var dfnPanel = document.querySelector(".dfn-panel[data-for='" + el.id + "']");
        if(dfnPanel) {
            dfnPanel.classList.add("on");
            var rect = el.getBoundingClientRect();
            dfnPanel.style.left = window.scrollX + rect.right + 5 + "px";
            dfnPanel.style.top = window.scrollY + rect.top + "px";
            var panelRect = dfnPanel.getBoundingClientRect();
            var panelWidth = panelRect.right - panelRect.left;
            if(panelRect.right > document.body.scrollWidth && (rect.left - (panelWidth + 5)) > 0) {
                // Reposition, because the panel is overflowing
                dfnPanel.style.left = window.scrollX + rect.left - (panelWidth + 5) + "px";
            }
        } else {
            console.log("Couldn't find .dfn-panel[data-for='" + el.id + "']");
        }
    } else if(target == "dfn-panel") {
        // Switch it to "activated" state, which pins it.
        el.classList.add("activated");
        el.style.left = null;
        el.style.top = null;
    }

});
</script>